package com.pi.shisan.service.audio;

import com.pi.shisan.service.util.ComponentManager;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import java.io.File;

public class WavPlayer extends AudioPlayer {

    private AudioInputStream audioInputStream;

    private long currentSamplesWritten;

    public WavPlayer(File audioFile, AudioEffectComponentsSupplier<ComponentManager.MusicEffectBaseComponent> musicEffectComponentsSupplier) throws Exception {
        super(audioFile, musicEffectComponentsSupplier);
        init();
    }

    private void init() throws Exception {
        currentSamplesWritten = 0;
        this.audioInputStream = AudioSystem.getAudioInputStream(audioFile);
        AudioFormat audioFormat = audioInputStream.getFormat();
        float frameRate = audioFormat.getFrameRate();
        if (frameRate != AudioSystem.NOT_SPECIFIED) {
            totalMilliseconds = (int) (((float) audioInputStream.getFrameLength() * 1000f / frameRate) + 0.5);
        } else {
            totalMilliseconds = (int) (((long) audioInputStream.available() / ((long) (audioFormat.getSampleSizeInBits() >> 3)) / (long) audioFormat.getChannels()) * 1000L / (long) audioFormat.getSampleRate());
        }
        DataLine.Info sourceLineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
        if (!AudioSystem.isLineSupported(sourceLineInfo)) {
            AudioFormat[] possibleFormats = AudioSystem.getTargetFormats(AudioFormat.Encoding.PCM_SIGNED, audioFormat);
            if (possibleFormats != null && possibleFormats.length != 0) {
                audioInputStream = AudioSystem.getAudioInputStream(possibleFormats[0], audioInputStream);
                audioFormat = audioInputStream.getFormat();
            }
        }
        getOutputBuffer(250 * audioFormat.getChannels() * (int) audioFormat.getSampleRate() / 1000);
    }

    @Override
    public void doDestroy() {
        if (audioInputStream != null) {
            try {
                audioInputStream.close();
            } catch (Exception e) {
            }
        }
    }

    @Override
    protected boolean doingPlay() throws Exception {
        if (audioOutputStream == null) {
            openSound(audioInputStream.getFormat());
        }
        int channels = audioInputStream.getFormat().getChannels();
        int sampleSizeInBytes = audioInputStream.getFormat().getSampleSizeInBits() >> 3;
        int sampleRate = (int) audioInputStream.getFormat().getSampleRate();
        byte[] buffer = getOutputBuffer(0);
        int len;
        while ((len = audioInputStream.read(buffer)) > 0) {
            writeSampleData(buffer, 0, len);
            currentSamplesWritten += (len / sampleSizeInBytes / channels);
            if (sampleRate != 0) {
                currentMilliseconds = (currentSamplesWritten * 1000L) / (long) sampleRate;
            }
            if (playerStatus.get() != PLAYING) {
                return false;
            }
        }
        return true;
    }

    @Override
    protected void reset() throws Exception {
        if (audioInputStream != null) {
            try {
                audioInputStream.close();
            } catch (Exception e) {
            }
        }
        init();
    }

    public static void main(String[] args) throws Exception{
        new WavPlayer(new File("music/clock/021.wav"),null).playOrResume();
    }
}
